/*

Wavefront OBJ

*/

#include "objmtl.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#ifndef OBJMTL_C
#define OBJMTL_C

static const char* delimiters = "\x20\x09\x0a\x0d";

OBJFILE* createOBJFILE() {
  OBJFILE* hobj = malloc(sizeof(OBJFILE));
  hobj->hvs = createMArray();
	hobj->hvns = createMArray();
	hobj->hvts = createMArray();
	hobj->hinds = createMArray();
	hobj->fs = createMArray();
  return hobj;
};

void freeOBJFILE(OBJFILE* hobj) {
  freeMArray(hobj->hvs);
  freeMArray(hobj->hvns);
  freeMArray(hobj->hvts);
  freeMArray(hobj->hinds);
  freeMArray(hobj->fs);
  free(hobj);
};

static void getInds(char* str, Inds* hi) {
	hi->d[0] = atoi(str);
	hi->d[1] = 0;
	hi->d[2] = 0;
	char* p = str;
	while(*p != 0x00 && *p != '/')
		p++;

	if(*p == '/') {
		p++;
		hi->d[1] = atoi(p);
	};

	while(*p != 0x00 && *p != '/')
		p++;

	if(*p == '/') {
		p++;
		hi->d[2] = atoi(p);
	};

};

void makeVBOVert(OBJFILE* hobj, int iv, int ivt, int ivn, Vec8f* hvvbo) {
	Vec3f* hv = hobj->hvs->d;
	Vec2f* hvt = hobj->hvts->d;
	Vec3f* hvn = hobj->hvns->d;
	memset(hvvbo, 0, sizeof(Vec8f));
	if(iv > 0) {
		iv--;
		memcpy(hvvbo, &hv[iv], sizeof(Vec3f));
	} else if(iv < 0) {
		iv = hobj->hvs->size/sizeof(Vec3f) + iv;
		memcpy(hvvbo, &hv[iv], sizeof(Vec3f));
	};

	if(ivt > 0) {
		ivt--;
		memcpy(&hvvbo->f[3], &hvt[ivt], sizeof(Vec2f));
	} else if(ivt < 0) {
		ivt = hobj->hvts->size/sizeof(Vec2f) + ivt;
		memcpy(&hvvbo->f[3], &hvt[ivt], sizeof(Vec2f));
	};

	if(ivn > 0) {
		ivn--;
		memcpy(&hvvbo->f[5], &hvn[ivn], sizeof(Vec3f));
	} else if(ivn < 0) {
		ivn = hobj->hvns->size/sizeof(Vec3f) + ivn;
		memcpy(&hvvbo->f[5], &hvn[ivn], sizeof(Vec3f));
	};
};

MArray* makeVBO(OBJFILE* hobj) {
  MArray* mVBO = createMArray();
  int* hf = hobj->fs->d;
	Inds* hi = hobj->hinds->d;

	for(int i=0; i<hobj->fs->size/sizeof(int) - 1; i++) {
		for(int k=hf[i]+2; k<hf[i+1]; k++) {
			Vec8f vvbo;
			makeVBOVert(hobj, hi[hf[i]].d[0], hi[hf[i]].d[1], hi[hf[i]].d[2], &vvbo);
			addMArrayEl(&vvbo, sizeof(Vec8f), mVBO);

			makeVBOVert(hobj, hi[k-1].d[0], hi[k-1].d[1], hi[k-1].d[2], &vvbo);
			addMArrayEl(&vvbo, sizeof(Vec8f), mVBO);

			makeVBOVert(hobj, hi[k].d[0], hi[k].d[1], hi[k].d[2], &vvbo);
			addMArrayEl(&vvbo, sizeof(Vec8f), mVBO);
		};
	};

  return mVBO;
};

OBJFILE* readOBJFILE(char* fname) {

	FILE* fp = fopen(fname, "r");

	Vec3f v, vn;
  Vec2f vt;

  OBJFILE* hobj = createOBJFILE();

	char buf[256];
	while(fgets(buf, 256, fp)) {
		char* last;
		char* token = strtok_r(buf, delimiters, &last);
		while(token) {
			if(token[0] == '#') break;
			if(strcmp(token, "v") == 0) {
				for(int i=0; i<3; i++) {
					token = strtok_r(NULL, delimiters, &last);
					v.f[i] = atof(token);
				};
				addMArrayEl(&v, sizeof(Vec3f), hobj->hvs);
			} else if(strcmp(token, "vt") == 0) {
				for(int i=0; i<2; i++) {
					token = strtok_r(NULL, delimiters, &last);
					vt.f[i] = atof(token);
          if(i == 1) vt.f[i] = 1.0f - vt.f[i]; // TODO: test it and delete
				};
				addMArrayEl(&vt, sizeof(Vec2f), hobj->hvts);
			} else if(strcmp(token, "vn") == 0) {
				for(int i=0; i<3; i++) {
					token = strtok_r(NULL, delimiters, &last);
					vn.f[i] = atof(token);
				};
				addMArrayEl(&vn, sizeof(Vec3f), hobj->hvns);
			} else if(strcmp(token, "f") == 0) {
				unsigned int sz = hobj->hinds->size/sizeof(Inds);
				addMArrayEl(&sz, sizeof(unsigned int), hobj->fs);
				while(token = strtok_r(NULL, delimiters, &last)) {
					Inds ids;
					getInds(token, &ids);
					addMArrayEl(&ids, sizeof(Inds), hobj->hinds);
				};
			};
			token = strtok_r(NULL, delimiters, &last);
		};
	};

	unsigned int sz = hobj->hinds->size/sizeof(Inds);
	addMArrayEl(&sz, sizeof(unsigned int), hobj->fs);

	return hobj;
};


#endif
